<?php

namespace Hilaoyu\Utils;


/**
 * Created by laoyu.
 * User: hilaoyu@qq.com
 * Date: 2018/3/8
 * Time: 9:45
 *
 *
 */
class UtilArr
{

    public static function toString($array, $glue = ';', $with_key = false, $key_glue = ':')
    {
        if (is_array($array)) {
            $tmp = [];
            foreach ($array as $k => $v) {
                $tmp[] = (is_string($k) && $with_key ? ($k . $key_glue) : '') . static::toString($v, $glue, $with_key);
            }
            return implode($glue, $tmp);
        }
        return (string)$array;
    }

    public static function toJson($array)
    {
        return json_encode($array);
    }

    public static function collapse($array){
        $results = [];

        foreach ($array as $values) {
            if (! is_array($values)) {
                continue;
            }

            $results[] = $values;
        }

        return array_merge([], ...$results);
    }

    public static function objectToArray(array $array, $key_name = 'key', $value_key = 'value')
    {
        $arr = [];

        foreach ($array as $k => $v) {
            if (!is_array($v)) {
                $v = [
                    $value_key => $v
                ];
            }
            $v[$key_name] = $k;

            $arr[] = $v;
        }

        return $arr;
    }

    /**
     * Set an array item to a given value using "dot" notation.
     *
     * If no key is given to the method, the entire array will be replaced.
     *
     * @param array $array
     * @param string $key
     * @param mixed $value
     * @return array
     */
    public static function set(&$array, $key, $value)
    {
        if (is_null($key)) {
            return $array = $value;
        }

        $keys = explode('.', $key);

        while (count($keys) > 1) {
            $key = array_shift($keys);

            // If the key doesn't exist at this depth, we will just create an empty array
            // to hold the next value, allowing us to create the arrays to hold final
            // values at the correct depth. Then we'll keep digging into the array.
            if (!isset($array[$key]) || !is_array($array[$key])) {
                $array[$key] = [];
            }

            $array = &$array[$key];
        }

        $array[array_shift($keys)] = $value;

        return $array;
    }

    /**
     * Get an item from an array using "dot" notation.
     *
     * @param \ArrayAccess|array $array
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    public static function get($array, $key, $default = null)
    {
        if (!is_array($array)) {
            return $default;
        }

        if (is_null($key)) {
            return $array;
        }

        if (array_key_exists($key, $array)) {
            return $array[$key];
        }

        if (strpos($key, '.') === false) {
            return $array[$key] ?? $default;
        }

        foreach (explode('.', $key) as $segment) {
            if (is_array($array) && array_key_exists($segment, $array)) {
                $array = $array[$segment];
            } else {
                return $default;
            }
        }

        return $array;
    }

    /**
     * Return the first element in an array passing a given truth test.
     *
     * @param array $array
     * @param callable|null $callback
     * @param mixed $default
     * @return mixed
     */
    public static function first($array, callable $callback = null, $default = null,$skip=0)
    {
        $i = 0 ;
        if (is_null($callback)) {
            if (empty($array)) {
                return value($default);
            }

            foreach ($array as $item) {
                if($i == $skip){
                    return $item;
                }
                $i++;
            }
        }

        foreach ($array as $key => $value) {
            if (call_user_func($callback, $value, $key)) {
                if($i == $skip){
                    return $value;
                }
                $i++;

            }
        }

        return value($default);
    }

    public static function filter($array, callable $callback){
        return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
    }

    /**
     * Return the last element in an array passing a given truth test.
     *
     * @param array $array
     * @param callable|null $callback
     * @param mixed $default
     * @return mixed
     */
    public static function last($array, callable $callback = null, $default = null)
    {
        if (is_null($callback)) {
            return empty($array) ? value($default) : end($array);
        }

        return static::first(array_reverse($array, true), $callback, $default);
    }

    /**
     * @param array $catalogs
     * @param string $parent
     * @param string $parent_key
     * @param string $id_key
     * @param string $children_key
     * @return array
     */
    static public function listToTree(array $catalogs, $parent = '', $parent_key = 'parent', $id_key = '_id', $children_key = 'children')
    {

        $tree = [];

        if (!empty($catalogs)) {
            $tree = array_filter($catalogs, function ($item) use ($parent, $parent_key) {
                $retrieved = static::get($item, $parent_key);

                return $retrieved == $parent;
            });


            foreach ($tree as &$item) {
                $item_id = static::get($item, $id_key);
                if (!$item_id) {
                    continue;
                }
                $children = static::listToTree($catalogs, $item_id, $parent_key, $id_key, $children_key);

                if (!empty($children)) {
                    $item[$children_key] = array_values($children);
                }
            }
        }

        return array_values($tree);
    }

    static public function treeToList(array $tree, $children_key = 'children', $initial_depth = 0, $except = '', $except_key = '_id')
    {

        $list = [];

        if (!empty($tree)) {

            foreach ($tree as $item) {
                $except_id = static::get($item, $except_key);
                if (
                    $except_id == $except
                    || (is_array($except) && in_array($except_id, $except))
                ) {
                    continue;
                }


                $children = static::get($item, $children_key);
                unset($item[$children_key]);

                if (is_array($item)) {
                    static::set($item, 'depth', $initial_depth);
                }

                $list[] = $item;

                if (!empty($children)) {
                    $children_list = static::treeToList($children, $children_key, $initial_depth + 1, $except, $except_key);
                    if (!empty($children_list)) {
                        $list = array_merge($list, $children_list);
                    }
                }

            }
        }

        return $list;
    }


    /**
     * 删除数组中的空值
     */
    static public function delNullValue(array $arr)
    {
        foreach ($arr as $key=>$value) {
            if (is_array($value)) {
                $arr[$key] = static::delNullValue($arr[$key]);
            } else if (is_null($value)) {
                unset($arr[$key]);
            }

        }

        return $arr;
    }
}
